package com.atguigu.gmall.weball.haha;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.annotation.AnnotationUtils;

import javax.sql.DataSource;
import java.lang.annotation.*;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Arrays;
import java.util.List;


/**
 * 引入缓存
 * 引入自定义结果集
 * ....
 *
 * 1、解析封装参数
 * 2、执行SQL
 * 3、封装结果
 *
 *
 * Spring：
 *  1、 IOC【DI】、（容器）项目中的所有有功能的对象（组件）把他们放在容器 [Map] 中。
 *      DI（依赖注入），需要哪些组件直接由Spring框架从容器中找到，放到JavaBean的属性中
 *  2、 AOP： 面向切面
 *
 *
 * 飞机厂：BeanFactory【ApplicationContext】
 *     1）、图纸[飞机参数]：BeanDefinition
 *          1、自己写
 *              <bean id="j20" class="J20">
 *                  <property name="fdj" value="taihang800缸"></property>
 *              </bean>
 *              <bean class="UserService">
 *                 <property name="userDao" ref="userDao"></property>
 *              </bean>
 *          2、用注解写
 *              @Bean
 *              J20  j20(){
 *                  return new J20("fdj=800gang");
 *              }
 *          3、从网上baidu
 *              datasource.xml
 *
 *          转化成计算机存档；
 *          Spring会把定义信息 BeanDefinition，保存到一个位置（BeanDefinitionRegistry【档案室】）
 *
 *
 *     2）、启动Spring。照着你传入的图纸，造指定的所有Bean
 *
 *          ioc = new ClassPathXmlApplicationContext("spring.xml");
 *          流水线
 *
 *
 *     3）、组件[飞机]：   Bean; 【Spring为所有组件进行增强的时候，都是在制造Bean的时候赋予更多功能的】
 *          遍历 BeanDefinitionRegistry 中的所有BeanDefinition信息，来制作Bean（按照图纸new对象）
 *          Autowired在此完成
 *          @Aspect
 *          Class UserService{
 *              @Autowired
 *              UserDao userDao;
 *
 *          }
 *
 *          @Service
 *          class UserHaha{
 *                  void hello();
 *          }
 *          //AOP 利用拦截器机制。cglib。 UserHaha 创建一个对象，重写了你的hello
 *          //调用AOP链   method.invoke()； super.hello();
 *          //并不是Java的动态代理；cglib和jdk动态代理。
 *
 *
 *
 *     4）、用组件：
 *          1、自己拿： ioc = getBean()
 *          2、自动注入： @Autowired等
 *
 *
 *
 *
 * 造飞机；
 *
 *     1、Spring启动的时候，容器中的各个组件怎么创建出来的，怎么保存的。spring各种注解是如何生效的？
 *
 *
 *
 */

@Aspect
class MyBatisAspec{

    Object around(ProceedingJoinPoint joinPoint){

        return null;
    }
}

public class MybatisFramework {

    public static void main(String[] args) {
//        MyBatisFactory.init();
        //1、获取我们Dao的代理
//        UserDao userDao = MyBatisFactory.getMapper(UserDao.class);
//
//        //2、调用代理对象
//        userDao.deleteById(1L);
//
//        userDao.updateById(2L);
        ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext("");

    }

}

//UserService a =new UserServiceSub()
class UserService{

    void haha (){

    }

    class UserServiceSub extends UserService{
        @Override
        void haha (){
            //执行AOP切面的所有方法
            super.haha();
        }

    }
}

class MyBatisFactory {

    private static DataSource dataSource;
    public MyBatisFactory(DataSource dataSource){
        dataSource = dataSource;
    }


    static <T> T getMapper(Class<T> dao) {

        Class<?>[] array = (Class<?>[]) Arrays.asList(dao).toArray();
        /**
         * ClassLoader loader,
         * Class<?>[] interfaces,
         * InvocationHandler h
         */
        Object proxy = Proxy.newProxyInstance(dao.getClassLoader(), array,
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println(".....");
                        Annotation[] annotations = method.getAnnotations();
                        Annotation annotation = annotations[0];
                        String value = (String) AnnotationUtils.getValue(annotation);

                        Type type = method.getGenericReturnType();


                        //TODO 找真的数据源
                        System.out.println("1、找到数据源");
                        System.out.println("2、获取连接");
                        if(annotation.annotationType().isAssignableFrom(MyDelete.class)){
                            //TODO 发送sql之前填充参数；截串操作，截到#{} 里面的内容。再去参数位置找对应的值
                            // Connection connection = dataSource.getConnection();
                            System.out.println("3、正在发送sql："+value);
                            //TODO 执行sql


                        }

                        if(annotation.annotationType().isAssignableFrom(MyQuery.class)){
                            System.out.println("3、正在发送sql："+value);
                            Connection connection = dataSource.getConnection();
                            PreparedStatement statement = connection.prepareStatement(value, Integer.parseInt(""));
                            ResultSet resultSet = statement.executeQuery();
                            //TODO 封装结果集
                            while (resultSet.next()) {
                                long id = resultSet.getLong(0);
                                String name = resultSet.getString(1);
                                //TODO 封装成指定JavaBean == type


                            }
                        }

                        if(annotation.annotationType().isAssignableFrom(MyUpdate.class)){
                            System.out.println("3、正在发送sql："+value);
                        }
                        if(annotation.annotationType().isAssignableFrom(MyInsert.class)){
                            System.out.println("3、正在发送sql："+value);
                        }
                        System.out.println("4、关闭连接");

                        //返回执行的结果
                        return null;
                    }
                });

        return (T) proxy;
    }
}


interface UserDao {

    @MyDelete("delete from hello where id=#{id}")
    void deleteById(Long id);


    @MyUpdate("update hello set a=1 where id=#{id}")
    void updateById(Long id);

    @MyQuery("update hello set a=1 where id=#{id}")
    List<Long> queryById(Long id);
}


@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@interface MyQuery {
    String value() default "";
}


@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@interface MyUpdate {
    String value() default "";
}

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@interface MyDelete {
    String value() default "";
}
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@interface MyInsert {
    String value() default "";
}